#include "yaml-cpp/emitter.h"
#include "emitterstate.h"
#include "emitterutils.h"
#include "indentation.h"
#include "yaml-cpp/exceptions.h"
#include <sstream>

namespace YAML
{
	Emitter::Emitter() : m_pState(new EmitterState)
	{
	}

	Emitter::Emitter(std::ostream& stream) : m_pState(new EmitterState), m_stream(stream)
	{
	}

	Emitter::~Emitter()
	{
	}

	const char *Emitter::c_str() const
	{
		return m_stream.str();
	}

	std::size_t Emitter::size() const
	{
		return m_stream.pos();
	}

	// state checking
	bool Emitter::good() const
	{
		return m_pState->good();
	}

	const std::string Emitter::GetLastError() const
	{
		return m_pState->GetLastError();
	}

	// global setters
	bool Emitter::SetOutputCharset(EMITTER_MANIP value)
	{
		return m_pState->SetOutputCharset(value, FmtScope::Global);
	}

	bool Emitter::SetStringFormat(EMITTER_MANIP value)
	{
		return m_pState->SetStringFormat(value, FmtScope::Global);
	}

	bool Emitter::SetBoolFormat(EMITTER_MANIP value)
	{
		bool ok = false;
		if (m_pState->SetBoolFormat(value, FmtScope::Global))
			ok = true;
		if (m_pState->SetBoolCaseFormat(value, FmtScope::Global))
			ok = true;
		if (m_pState->SetBoolLengthFormat(value, FmtScope::Global))
			ok = true;
		return ok;
	}

	bool Emitter::SetIntBase(EMITTER_MANIP value)
	{
		return m_pState->SetIntFormat(value, FmtScope::Global);
	}

	bool Emitter::SetSeqFormat(EMITTER_MANIP value)
	{
		return m_pState->SetFlowType(GroupType::Seq, value, FmtScope::Global);
	}

	bool Emitter::SetMapFormat(EMITTER_MANIP value)
	{
		bool ok = false;
		if (m_pState->SetFlowType(GroupType::Map, value, FmtScope::Global))
			ok = true;
		if (m_pState->SetMapKeyFormat(value, FmtScope::Global))
			ok = true;
		return ok;
	}

	bool Emitter::SetIndent(unsigned n)
	{
		return m_pState->SetIndent(n, FmtScope::Global);
	}

	bool Emitter::SetPreCommentIndent(unsigned n)
	{
		return m_pState->SetPreCommentIndent(n, FmtScope::Global);
	}

	bool Emitter::SetPostCommentIndent(unsigned n)
	{
		return m_pState->SetPostCommentIndent(n, FmtScope::Global);
	}

	bool Emitter::SetFloatPrecision(unsigned n)
	{
		return m_pState->SetFloatPrecision(n, FmtScope::Global);
	}

	bool Emitter::SetDoublePrecision(unsigned n)
	{
		return m_pState->SetDoublePrecision(n, FmtScope::Global);
	}

	// SetLocalValue
	// . Either start/end a group, or set a modifier locally
	Emitter& Emitter::SetLocalValue(EMITTER_MANIP value)
	{
		if (!good())
			return *this;

		switch (value) {
		case BeginDoc:
			EmitBeginDoc();
			break;
		case EndDoc:
			EmitEndDoc();
			break;
		case BeginSeq:
			EmitBeginSeq();
			break;
		case EndSeq:
			EmitEndSeq();
			break;
		case BeginMap:
			EmitBeginMap();
			break;
		case EndMap:
			EmitEndMap();
			break;
		case Key:
		case Value:
			// deprecated (these can be deduced by the parity of nodes in a map)
			break;
		case TagByKind:
			EmitKindTag();
			break;
		case Newline:
			EmitNewline();
			break;
		default:
			m_pState->SetLocalValue(value);
			break;
		}
		return *this;
	}

	Emitter& Emitter::SetLocalIndent(const _Indent& indent)
	{
		m_pState->SetIndent(indent.value, FmtScope::Local);
		return *this;
	}

	Emitter& Emitter::SetLocalPrecision(const _Precision& precision)
	{
		if (precision.floatPrecision >= 0)
			m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local);
		if (precision.doublePrecision >= 0)
			m_pState->SetDoublePrecision(precision.doublePrecision, FmtScope::Local);
		return *this;
	}

	// EmitBeginDoc
	void Emitter::EmitBeginDoc()
	{
		if (!good())
			return;

		if (m_pState->CurGroupType() != GroupType::None) {
			m_pState->SetError("Unexpected begin document");
			return;
		}

		if (m_pState->HasAnchor() || m_pState->HasTag()) {
			m_pState->SetError("Unexpected begin document");
			return;
		}

		if (m_stream.col() > 0)
			m_stream << "\n";
		m_stream << "---\n";

		m_pState->StartedDoc();
	}

	// EmitEndDoc
	void Emitter::EmitEndDoc()
	{
		if (!good())
			return;

		if (m_pState->CurGroupType() != GroupType::None) {
			m_pState->SetError("Unexpected begin document");
			return;
		}

		if (m_pState->HasAnchor() || m_pState->HasTag()) {
			m_pState->SetError("Unexpected begin document");
			return;
		}

		if (m_stream.col() > 0)
			m_stream << "\n";
		m_stream << "...\n";
	}

	// EmitBeginSeq
	void Emitter::EmitBeginSeq()
	{
		if (!good())
			return;

		PrepareNode(m_pState->NextGroupType(GroupType::Seq));

		m_pState->StartedGroup(GroupType::Seq);
	}

	// EmitEndSeq
	void Emitter::EmitEndSeq()
	{
		if (!good())
			return;

		if (m_pState->CurGroupChildCount() == 0)
			m_pState->ForceFlow();

		if (m_pState->CurGroupFlowType() == FlowType::Flow) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(m_pState->CurIndent());
			if (m_pState->CurGroupChildCount() == 0)
				m_stream << "[";
			m_stream << "]";
		}

		m_pState->EndedGroup(GroupType::Seq);
	}

	// EmitBeginMap
	void Emitter::EmitBeginMap()
	{
		if (!good())
			return;

		PrepareNode(m_pState->NextGroupType(GroupType::Map));

		m_pState->StartedGroup(GroupType::Map);
	}

	// EmitEndMap
	void Emitter::EmitEndMap()
	{
		if (!good())
			return;

		if (m_pState->CurGroupChildCount() == 0)
			m_pState->ForceFlow();

		if (m_pState->CurGroupFlowType() == FlowType::Flow) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(m_pState->CurIndent());
			if (m_pState->CurGroupChildCount() == 0)
				m_stream << "{";
			m_stream << "}";
		}

		m_pState->EndedGroup(GroupType::Map);
	}

	// EmitNewline
	void Emitter::EmitNewline()
	{
		if (!good())
			return;

		PrepareNode(EmitterNodeType::None);
		m_stream << "\n";
		m_pState->SetNonContent();
	}

	bool Emitter::CanEmitNewline() const
	{
		return true;
	}

	// Put the stream in a state so we can simply write the next node
	// E.g., if we're in a sequence, write the "- "
	void Emitter::PrepareNode(EmitterNodeType::value child)
	{
		switch (m_pState->CurGroupNodeType()) {
		case EmitterNodeType::None:
			PrepareTopNode(child);
			break;
		case EmitterNodeType::FlowSeq:
			FlowSeqPrepareNode(child);
			break;
		case EmitterNodeType::BlockSeq:
			BlockSeqPrepareNode(child);
			break;
		case EmitterNodeType::FlowMap:
			FlowMapPrepareNode(child);
			break;
		case EmitterNodeType::BlockMap:
			BlockMapPrepareNode(child);
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
			assert(false);
			break;
		}
	}

	void Emitter::PrepareTopNode(EmitterNodeType::value child)
	{
		if (child == EmitterNodeType::None)
			return;

		if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0) {
			if (child != EmitterNodeType::None)
				EmitBeginDoc();
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			// TODO: if we were writing null, and
			// we wanted it blank, we wouldn't want a space
			SpaceOrIndentTo(m_pState->HasBegunContent(), 0);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			if (m_pState->HasBegunNode())
				m_stream << "\n";
			break;
		}
	}

	void Emitter::FlowSeqPrepareNode(EmitterNodeType::value child)
	{
		const unsigned lastIndent = m_pState->LastIndent();

		if (!m_pState->HasBegunNode()) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(lastIndent);
			if (m_pState->CurGroupChildCount() == 0)
				m_stream << "[";
			else
				m_stream << ",";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, lastIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			assert(false);
			break;
		}
	}

	void Emitter::BlockSeqPrepareNode(EmitterNodeType::value child)
	{
		const unsigned curIndent = m_pState->CurIndent();
		const unsigned nextIndent = curIndent + m_pState->CurGroupIndent();

		if (child == EmitterNodeType::None)
			return;

		if (!m_pState->HasBegunContent()) {
			if (m_pState->CurGroupChildCount() > 0 || m_stream.comment()) {
				m_stream << "\n";
			}
			m_stream << IndentTo(curIndent);
			m_stream << "-";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent(), nextIndent);
			break;
		case EmitterNodeType::BlockSeq:
			m_stream << "\n";
			break;
		case EmitterNodeType::BlockMap:
			if (m_pState->HasBegunContent() || m_stream.comment())
				m_stream << "\n";
			break;
		}
	}

	void Emitter::FlowMapPrepareNode(EmitterNodeType::value child)
	{
		if (m_pState->CurGroupChildCount() % 2 == 0) {
			if (m_pState->GetMapKeyFormat() == LongKey)
				m_pState->SetLongKey();

			if (m_pState->CurGroupLongKey())
				FlowMapPrepareLongKey(child);
			else
				FlowMapPrepareSimpleKey(child);
		}
		else {
			if (m_pState->CurGroupLongKey())
				FlowMapPrepareLongKeyValue(child);
			else
				FlowMapPrepareSimpleKeyValue(child);
		}
	}

	void Emitter::FlowMapPrepareLongKey(EmitterNodeType::value child)
	{
		const unsigned lastIndent = m_pState->LastIndent();

		if (!m_pState->HasBegunNode()) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(lastIndent);
			if (m_pState->CurGroupChildCount() == 0)
				m_stream << "{ ?";
			else
				m_stream << ", ?";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, lastIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			assert(false);
			break;
		}
	}

	void Emitter::FlowMapPrepareLongKeyValue(EmitterNodeType::value child)
	{
		const unsigned lastIndent = m_pState->LastIndent();

		if (!m_pState->HasBegunNode()) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(lastIndent);
			m_stream << ":";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, lastIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			assert(false);
			break;
		}
	}

	void Emitter::FlowMapPrepareSimpleKey(EmitterNodeType::value child)
	{
		const unsigned lastIndent = m_pState->LastIndent();

		if (!m_pState->HasBegunNode()) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(lastIndent);
			if (m_pState->CurGroupChildCount() == 0)
				m_stream << "{";
			else
				m_stream << ",";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, lastIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			assert(false);
			break;
		}
	}

	void Emitter::FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child)
	{
		const unsigned lastIndent = m_pState->LastIndent();

		if (!m_pState->HasBegunNode()) {
			if (m_stream.comment())
				m_stream << "\n";
			m_stream << IndentTo(lastIndent);
			m_stream << ":";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, lastIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			assert(false);
			break;
		}
	}

	void Emitter::BlockMapPrepareNode(EmitterNodeType::value child)
	{
		if (m_pState->CurGroupChildCount() % 2 == 0) {
			if (m_pState->GetMapKeyFormat() == LongKey)
				m_pState->SetLongKey();
			if (child == EmitterNodeType::BlockSeq || child == EmitterNodeType::BlockMap)
				m_pState->SetLongKey();

			if (m_pState->CurGroupLongKey())
				BlockMapPrepareLongKey(child);
			else
				BlockMapPrepareSimpleKey(child);
		}
		else {
			if (m_pState->CurGroupLongKey())
				BlockMapPrepareLongKeyValue(child);
			else
				BlockMapPrepareSimpleKeyValue(child);
		}
	}

	void Emitter::BlockMapPrepareLongKey(EmitterNodeType::value child)
	{
		const unsigned curIndent = m_pState->CurIndent();
		const std::size_t childCount = m_pState->CurGroupChildCount();

		if (child == EmitterNodeType::None)
			return;

		if (!m_pState->HasBegunContent()) {
			if (childCount > 0) {
				m_stream << "\n";
			}
			if (m_stream.comment()) {
				m_stream << "\n";
			}
			m_stream << IndentTo(curIndent);
			m_stream << "?";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(true, curIndent + 1);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			break;
		}
	}

	void Emitter::BlockMapPrepareLongKeyValue(EmitterNodeType::value child)
	{
		const unsigned curIndent = m_pState->CurIndent();

		if (child == EmitterNodeType::None)
			return;

		if (!m_pState->HasBegunContent()) {
			m_stream << "\n";
			m_stream << IndentTo(curIndent);
			m_stream << ":";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			SpaceOrIndentTo(true, curIndent + 1);
			break;
		}
	}

	void Emitter::BlockMapPrepareSimpleKey(EmitterNodeType::value child)
	{
		const unsigned curIndent = m_pState->CurIndent();
		const std::size_t childCount = m_pState->CurGroupChildCount();

		if (child == EmitterNodeType::None)
			return;

		if (!m_pState->HasBegunNode()) {
			if (childCount > 0) {
				m_stream << "\n";
			}
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(m_pState->HasBegunContent(), curIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			break;
		}
	}

	void Emitter::BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child)
	{
		const unsigned curIndent = m_pState->CurIndent();
		const unsigned nextIndent = curIndent + m_pState->CurGroupIndent();

		if (!m_pState->HasBegunNode()) {
			m_stream << ":";
		}

		switch (child) {
		case EmitterNodeType::None:
			break;
		case EmitterNodeType::Property:
		case EmitterNodeType::Scalar:
		case EmitterNodeType::FlowSeq:
		case EmitterNodeType::FlowMap:
			SpaceOrIndentTo(true, nextIndent);
			break;
		case EmitterNodeType::BlockSeq:
		case EmitterNodeType::BlockMap:
			m_stream << "\n";
			break;
		}
	}

	// SpaceOrIndentTo
	// . Prepares for some more content by proper spacing
	void Emitter::SpaceOrIndentTo(bool requireSpace, unsigned indent)
	{
		if (m_stream.comment())
			m_stream << "\n";
		if (m_stream.col() > 0 && requireSpace)
			m_stream << " ";
		m_stream << IndentTo(indent);
	}

	void Emitter::PrepareIntegralStream(std::stringstream& stream) const
	{
		switch (m_pState->GetIntFormat()) {
		case Dec:
			stream << std::dec;
			break;
		case Hex:
			stream << "0x";
			stream << std::hex;
			break;
		case Oct:
			stream << "0";
			stream << std::oct;
			break;
		default:
			assert(false);
		}
	}

	void Emitter::StartedScalar()
	{
		m_pState->StartedScalar();
	}

	// *******************************************************************************************
	// overloads of Write

	Emitter& Emitter::Write(const std::string& str)
	{
		if (!good())
			return *this;

		const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
		const StringFormat::value strFormat = Utils::ComputeStringFormat(str, m_pState->GetStringFormat(), m_pState->CurGroupFlowType(), escapeNonAscii);

		if (strFormat == StringFormat::Literal)
			m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);

		PrepareNode(EmitterNodeType::Scalar);

		switch (strFormat) {
		case StringFormat::Plain:
			m_stream << str;
			break;
		case StringFormat::SingleQuoted:
			Utils::WriteSingleQuotedString(m_stream, str);
			break;
		case StringFormat::DoubleQuoted:
			Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
			break;
		case StringFormat::Literal:
			Utils::WriteLiteralString(m_stream, str, m_pState->CurIndent() + m_pState->GetIndent());
			break;
		}

		StartedScalar();

		return *this;
	}

	unsigned Emitter::GetFloatPrecision() const
	{
		return m_pState->GetFloatPrecision();
	}

	unsigned Emitter::GetDoublePrecision() const
	{
		return m_pState->GetDoublePrecision();
	}

	const char *Emitter::ComputeFullBoolName(bool b) const
	{
		const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat());
		const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
		switch (mainFmt) {
		case YesNoBool:
			switch (caseFmt) {
			case UpperCase: return b ? "YES" : "NO";
			case CamelCase: return b ? "Yes" : "No";
			case LowerCase: return b ? "yes" : "no";
			default: break;
			}
			break;
		case OnOffBool:
			switch (caseFmt) {
			case UpperCase: return b ? "ON" : "OFF";
			case CamelCase: return b ? "On" : "Off";
			case LowerCase: return b ? "on" : "off";
			default: break;
			}
			break;
		case TrueFalseBool:
			switch (caseFmt) {
			case UpperCase: return b ? "TRUE" : "FALSE";
			case CamelCase: return b ? "True" : "False";
			case LowerCase: return b ? "true" : "false";
			default: break;
			}
			break;
		default:
			break;
		}
		return b ? "y" : "n"; // should never get here, but it can't hurt to give these answers
	}

	Emitter& Emitter::Write(bool b)
	{
		if (!good())
			return *this;

		PrepareNode(EmitterNodeType::Scalar);

		const char *name = ComputeFullBoolName(b);
		if (m_pState->GetBoolLengthFormat() == ShortBool)
			m_stream << name[0];
		else
			m_stream << name;

		StartedScalar();

		return *this;
	}

	Emitter& Emitter::Write(char ch)
	{
		if (!good())
			return *this;

		PrepareNode(EmitterNodeType::Scalar);
		Utils::WriteChar(m_stream, ch);
		StartedScalar();

		return *this;
	}

	Emitter& Emitter::Write(const _Alias& alias)
	{
		if (!good())
			return *this;

		if (m_pState->HasAnchor() || m_pState->HasTag()) {
			m_pState->SetError(ErrorMsg::INVALID_ALIAS);
			return *this;
		}

		PrepareNode(EmitterNodeType::Scalar);

		if (!Utils::WriteAlias(m_stream, alias.content)) {
			m_pState->SetError(ErrorMsg::INVALID_ALIAS);
			return *this;
		}

		StartedScalar();

		return *this;
	}

	Emitter& Emitter::Write(const _Anchor& anchor)
	{
		if (!good())
			return *this;

		if (m_pState->HasAnchor()) {
			m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
			return *this;
		}

		PrepareNode(EmitterNodeType::Property);

		if (!Utils::WriteAnchor(m_stream, anchor.content)) {
			m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
			return *this;
		}

		m_pState->SetAnchor();

		return *this;
	}

	Emitter& Emitter::Write(const _Tag& tag)
	{
		if (!good())
			return *this;

		if (m_pState->HasTag()) {
			m_pState->SetError(ErrorMsg::INVALID_TAG);
			return *this;
		}

		PrepareNode(EmitterNodeType::Property);

		bool success = false;
		if (tag.type == _Tag::Type::Verbatim)
			success = Utils::WriteTag(m_stream, tag.content, true);
		else if (tag.type == _Tag::Type::PrimaryHandle)
			success = Utils::WriteTag(m_stream, tag.content, false);
		else
			success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);

		if (!success) {
			m_pState->SetError(ErrorMsg::INVALID_TAG);
			return *this;
		}

		m_pState->SetTag();

		return *this;
	}

	void Emitter::EmitKindTag()
	{
		Write(LocalTag(""));
	}

	Emitter& Emitter::Write(const _Comment& comment)
	{
		if (!good())
			return *this;

		PrepareNode(EmitterNodeType::None);

		if (m_stream.col() > 0)
			m_stream << Indentation(m_pState->GetPreCommentIndent());
		Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent());

		m_pState->SetNonContent();

		return *this;
	}

	Emitter& Emitter::Write(const _Null& /*null*/)
	{
		if (!good())
			return *this;

		PrepareNode(EmitterNodeType::Scalar);

		m_stream << "~";

		StartedScalar();

		return *this;
	}

	Emitter& Emitter::Write(const Binary& binary)
	{
		Write(SecondaryTag("binary"));

		if (!good())
			return *this;

		PrepareNode(EmitterNodeType::Scalar);
		Utils::WriteBinary(m_stream, binary);
		StartedScalar();

		return *this;
	}
}